package com.example.yt_app.Urils;

import androidx.annotation.Nullable;

import org.jetbrains.annotations.NotNull;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;

/**
 * Created by dell on 2021/7/9.
 */
@SuppressWarnings("ALL")
public class OkHttpHelper {
    private OkHttpClient client;
    private Request request;

    private static OkHttpHelper instance = null;
    private OkHttpHelper() {
        initOkHttp();//初始化
    }

    public static OkHttpHelper getInstance() {//单例模式
        if (instance == null) {
            synchronized (OkHttpHelper.class) {
                if (instance == null) {
                    instance = new OkHttpHelper();
                }
            }
        }
        return instance;
    }

    private void initOkHttp() {
        client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .build();
    }
    //设置问GET请求，设置下载网址
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    public OkHttpHelper setDownloadUrl(String url) {
        request = new Request.Builder()
                .url(url)
                //.header("RANGE","")//断点续传时需要使用的
                .get()
                .build();
        return this;
    }
    //设置下载路径，开始下载
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    public void startDownload(final String path, final DownloadCallback callback) {
        if (client == null) {
            initOkHttp();
        }
        OkHttpClient okHttpClient = client.newBuilder().addInterceptor(new MyInterceptor(callback)).build();//插入自定义的MyInterceptor()拦截器
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                callback.fail(e.getMessage());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                download(response,path);
                callback.complete("完成");
            }
        });
    }
    //创建MyInterceptor类，实现Interceptor 拦截器
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    static class MyInterceptor implements Interceptor {
        DownloadCallback callback;
        public MyInterceptor(DownloadCallback callback) {
            super();
            this.callback = callback;
        }

        @NotNull
        @Override
        public Response intercept(@NotNull Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            return response.newBuilder().body(new MyResponseBody(response,callback)).build();
        }
    }
    //创建MyResponseBody 类，继承 ResponseBody类
    @SuppressWarnings("AlibabaCommentsMustBeJavadocFormat")
    static class MyResponseBody extends ResponseBody {
        Response response;
        DownloadCallback callback;

        MyResponseBody(Response response,DownloadCallback callback) {
            super();
            this.response = response;
            this.callback = callback;
        }

        @Override
        public long contentLength() {
            //获取文件的总字节数
            callback.start(response.body().contentLength());
            return response.body().contentLength();
        }

        @Nullable
        @Override
        public MediaType contentType() {
            //可以获取文件的类型
            return response.body().contentType();
        }

        @NotNull
        @Override
        public BufferedSource source() {
            contentLength();
            contentType();
            //可以获取文件资源
            return Okio.buffer(new ForwardingSource(response.body().source()) {
                long bytesLength=0;
                @Override
                public long read(@NotNull Buffer sink, long byteCount) throws IOException {
                    //获取下载进度
                    final long bytesRead = super.read(sink, byteCount);
                    bytesLength += bytesRead;
                    callback.loading(bytesLength);
                    return bytesRead;
                }
            });
        }
    }
    //注：MyResponseBody里的三个接口contentLength,contentType,source,并不会程序自己主动调用执行,需要人为被动执行；
    //source接口的执行,在程序执行到download方法的“InputStream is = response.body().byteStream();”时才会被调用；
    // 然后我们自己调用contentLength(),contentType()方法去执行,
    // 或者我们在download方法的“InputStream is = response.body().byteStream();”上面添加两行代码response.body().contentLength();,response.body().contentType();
    //下载，执行下载、保存
    @SuppressWarnings({"AlibabaRemoveCommentedCode", "AlibabaCommentsMustBeJavadocFormat"})
    public static void download(Response response, String path) throws IOException {
        //response.body().contentLength();
        //response.body().contentType();
        InputStream is = response.body().byteStream();//拿到资源，转为字节流
        BufferedInputStream bis = new BufferedInputStream(is);
        FileOutputStream fos = new FileOutputStream(new File(path));//设置需要保存的位置，及文件
        byte[] bytes = new byte[1024];
        int len;
        while ((len = is.read(bytes)) != -1) {
            fos.write(bytes, 0, len);//保存
        }
        fos.flush();
        is.close();
        bis.close();
        fos.close();
    }
    //一些必要的接口
    @SuppressWarnings({"AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc", "AlibabaCommentsMustBeJavadocFormat"})
    public interface DownloadCallback {	//各种下载需要的接口
        //开始下载
        @SuppressWarnings("AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc")
        void start(long max);			//传入文件总字节数
        //正在下载
        @SuppressWarnings("AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc")
        void loading(long progress);	//传入已下载的字节数
        //下载完成
        @SuppressWarnings("AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc")
        void complete(String msg);		//传入成功信息
        //请求失败
        @SuppressWarnings("AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc")
        void fail( String message);		//传入错误信息
    }
}
